<html>
<head>
<script type="text/javascript" src="jquery.min.js">
</script>
<script type="text/javascript">
$(function() {
    $('#clean').click( function() {
        code = $('#code').html()
        code = code.replace(/(\\n)/gm,"");
        code = code.replace(/\/\*.+?\*\/|\/\/.*(?=[\n\r])/g, '');       
        code = code.replace(/(\\")/gm,'"');        

         $('#code').html(code);
    })
    
})
</script>

</head>
<form name="form1">
<textarea id="code" name="code" rows = "15"  cols="70">
var $builtinmodule = function(name)\n{\n    var mod = {};\n\n    Sk.simplegui = {};\n\n    var timers = [];\n    var frames = [];\n    var sounds = [];\n\n    var fontfaces = {\n        'serif': true,\n        'sans-serif': true,\n        'monospace': true\n    };\n\n    // Cross-browser requestAnimationFrame\n    (function() {\n        var lastTime = 0;\n        var vendors = ['ms', 'moz', 'webkit', 'o'];\n        for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {\n            window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];\n            window.cancelAnimationFrame = \n                window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];\n        }\n        \n        if (!window.requestAnimationFrame)\n            window.requestAnimationFrame = function(callback, element) {\n                var currTime = new Date().getTime();\n                var timeToCall = Math.max(0, 16 - (currTime - lastTime));\n                var id = window.setTimeout(function() { callback(currTime + timeToCall); }, \n                                           timeToCall);\n                lastTime = currTime + timeToCall;\n                return id;\n            };\n        \n        if (!window.cancelAnimationFrame)\n            window.cancelAnimationFrame = function(id) {\n                clearTimeout(id);\n            };\n    }());\n\n \n    Sk.simplegui.cleanup = function () {\n        // Cleanup the module - kill all timers, release all resources\n        for (var i = 0; i < timers.length; i++) {\n            // Stop the timer, if it's running\n            Sk.misceval.callsim(timers[i].stop, timers[i]);\n        };\n        timers = [];\n\n        for (var i = 0; i < sounds.length; i++) {\n            // Stop the sound, if it's playing\n            Sk.misceval.callsim(sounds[i].pause, sounds[i]);\n        };\n        sounds = [];\n\n        for (i=0; i < frames.length; i++) {\n            // Close the window, if it's open\n            Sk.misceval.callsim(frames[i].stop, frames[i]);\n        };\n        frames = [];\n    };\n\n    // goog.require(\"goog.events\");\n    // goog.require(\"goog.events.KeyCodes\");\n    // goog.require(\"goog.events.KeyHandler\");\n\n    // Images\n    var image = function($gbl, $loc) {\n        $loc.__init__ = new Sk.builtin.func(function(self, image_file) {\n            self.image = new Image();\n            self.image.src = Sk.ffi.unwrapo(image_file);\n            self.__class__ = mod.Image;\n        });\n\n        // $loc.wait = new Sk.builtin.func(function(self) {\n        // });\n\n        $loc.get_width = new Sk.builtin.func(function(self) {\n            Sk.builtin.pyCheckArgs(\"get_width\", arguments, 1, 1);\n\n            return Sk.builtin.assk$(self.image.width, Sk.builtin.nmber.int$);\n        });\n\n        $loc.get_height = new Sk.builtin.func(function(self) {\n            Sk.builtin.pyCheckArgs(\"get_height\", arguments, 1, 1);\n\n            return Sk.builtin.assk$(self.image.height, Sk.builtin.nmber.int$);\n        });\n    };\n\n    mod.Image = Sk.misceval.buildClass(mod, image, 'Image', []);\n\n    mod.load_image = new Sk.builtin.func(function(image_file) {\n        Sk.builtin.pyCheckArgs(\"load_image\", arguments, 1, 1);\n        if (!Sk.builtin.checkString(image_file)) {\n            throw new Sk.builtin.TypeError(\"expected string\");\n        };\n\n        return Sk.misceval.callsim(mod.Image, image_file);\n    });\n\n    // Sounds\n    var sound = function($gbl, $loc) {\n        $loc.__init__ = new Sk.builtin.func(function(self, sound_file) {\n            if (Sk.builtin.checkString(sound_file)) {\n                sound_file = Sk.ffi.unwrapo(sound_file);\n            }\n\n            self.sound = new Audio(sound_file);\n            self.__class__ = mod.Sound;\n\n            // Store sound\n            sounds.push(self);\n        });\n\n        $loc.set_volume = new Sk.builtin.func(function (self, vol) {\n            Sk.builtin.pyCheckArgs(\"set_volume\", arguments, 2, 2);\n            if (!Sk.builtin.checkNumber(vol)) {\n                throw new Sk.builtin.TypeError(\"Volume must be a number\");\n            };\n            vol = Sk.builtin.asnum$(vol);\n\n            if ((vol >= 0) && (vol <= 1)) {\n                self.sound.volume = vol;                \n            } else {\n                throw new Sk.builtin.ValueError(\"Volume must be between 0 and 1\");\n            };\n\n            return Sk.builtin.none.none$;\n        });\n\n        // $loc.wait = new Sk.builtin.func(function(self) {\n        // });\n\n        $loc.play = new Sk.builtin.func(function(self) {\n            Sk.builtin.pyCheckArgs(\"play\", arguments, 1, 1);\n\n            self.sound.play();\n\n            return Sk.builtin.none.none$;\n        });\n\n        $loc.pause = new Sk.builtin.func(function(self) {\n            Sk.builtin.pyCheckArgs(\"pause\", arguments, 1, 1);\n\n            self.sound.pause();\n\n            return Sk.builtin.none.none$;\n        });\n\n        $loc.rewind = new Sk.builtin.func(function(self) {\n            Sk.builtin.pyCheckArgs(\"rewind\", arguments, 1, 1);\n\n            self.sound.pause();\n            if (self.sound.currentTime) {\n                self.sound.currentTime = 0;                \n            };\n\n            return Sk.builtin.none.none$;\n        });\n    };\n\n    mod.Sound = Sk.misceval.buildClass(mod, sound, 'Sound', []);\n\n    mod.load_sound = new Sk.builtin.func(function(sound_file) {\n        Sk.builtin.pyCheckArgs(\"load_image\", arguments, 1, 1);\n        if (!Sk.builtin.checkString(sound_file)) {\n            throw new Sk.builtin.TypeError(\"expected string\");\n        };\n\n        return Sk.misceval.callsim(mod.Sound, sound_file);\n    });\n\n    function base64_encode (data) {\n        // http://kevin.vanzonneveld.net\n        // +   original by: Tyler Akins (http://rumkin.com)\n        // +   improved by: Bayron Guevara\n        // +   improved by: Thunder.m\n        // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)\n        // +   bugfixed by: Pellentesque Malesuada\n        // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)\n        // +   improved by: Rafa\u0142 Kukawski (http://kukawski.pl)\n        // *     example 1: base64_encode('Kevin van Zonneveld');\n        // *     returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='\n        // mozilla has this native\n        // - but breaks in 2.0.0.12!\n        //if (typeof this.window['btoa'] == 'function') {\n        //    return btoa(data);\n        //}\n        var b64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\n        var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,\n        ac = 0,\n        enc = \"\",\n        tmp_arr = [];\n        \n        if (!data) {\n            return data;\n        }\n        \n        do { // pack three octets into four hexets\n            o1 = data[i++];\n            o2 = data[i++];\n            o3 = data[i++];\n            \n            bits = o1 << 16 | o2 << 8 | o3;\n            \n            h1 = bits >> 18 & 0x3f;\n            h2 = bits >> 12 & 0x3f;\n            h3 = bits >> 6 & 0x3f;\n            h4 = bits & 0x3f;\n            \n            // use hexets to index into b64, and append result to encoded string\n            tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);\n        } while (i < data.length);\n        \n        enc = tmp_arr.join('');\n        \n        var r = data.length % 3;\n        \n        return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);   \n    };\n\n    mod.create_sound = new Sk.builtin.func(function(sound_data, sample_rate, num_channels) {\n        Sk.builtin.pyCheckArgs(\"create_sound\", arguments, 1, 3);\n        if (!Sk.builtin.checkSequence(sound_data)) {\n            throw new Sk.builtin.TypeError(\"sound_data must be a sequence\");\n        }\n        if (sample_rate !== undefined) {\n            if (!Sk.builtin.checkInt(sample_rate)) {\n                throw new Sk.builtin.TypeError(\"sample_rate must be an integer\");\n            }\n            sample_rate = Sk.builtin.asnum$(sample_rate);\n        }\n        else {\n            sample_rate = 8000;\n        }\n        if (num_channels !== undefined) {\n            if (!Sk.builtin.checkInt(num_channels)) {\n                throw new Sk.builtin.TypeError(\"num_channels must be an integer\");\n            }\n            num_channels = Sk.builtin.asnum$(num_channels);\n        }\n        else {\n            num_channels = 1;\n        }\n\n        function getByte(num, b) {\n            return (num >> (b*8)) & 0xff;\n        }\n\n        var bitsPerSample = 8;\n        var blockAlign = (num_channels * bitsPerSample) / 8;\n        var byteRate = sample_rate * blockAlign;\n        var numSamples = sound_data.sq$length() / num_channels;\n        var subchunk2size = numSamples * blockAlign;\n        var chunksize = 36 + subchunk2size;\n\n        // Header\n        var data = [\n            0x52, 0x49, 0x46, 0x46,  // ChunkID: \"RIFF\"\n            getByte(chunksize, 0),\n            getByte(chunksize, 1),\n            getByte(chunksize, 2),\n            getByte(chunksize, 3),   // ChunkSize: 36 + SubChunk2Size\n            0x57, 0x41, 0x56, 0x45,  // Format: \"WAVE\"\n            0x66, 0x6d, 0x74, 0x20,  // Subchunk1ID: \"fmt \"\n            0x10, 0x00, 0x00, 0x00,  // Subchunk1Size: 16\n            0x01, 0x00,              // AudioFormat: 1 (PCM)\n            getByte(num_channels, 0), \n            getByte(num_channels, 1), // NumChannels\n            getByte(sample_rate, 0),\n            getByte(sample_rate, 1),\n            getByte(sample_rate, 2),\n            getByte(sample_rate, 3), // SampleRate\n            getByte(byteRate, 0),\n            getByte(byteRate, 1),\n            getByte(byteRate, 2),\n            getByte(byteRate, 3),    // ByteRate\n            getByte(blockAlign, 0),\n            getByte(blockAlign, 1),  // BlockAlign\n            getByte(bitsPerSample, 0),\n            getByte(bitsPerSample, 1), // BitsPerSample\n            0x64, 0x61, 0x74, 0x61,   // Subchunk2ID: \"data\"\n            getByte(subchunk2size, 0), \n            getByte(subchunk2size, 1), \n            getByte(subchunk2size, 2), \n            getByte(subchunk2size, 3) // Subchunk2Size\n        ];\n\n        var it = sound_data.tp$iter();\n        var i;\n        for (i = it.tp$iternext(); i !== undefined; i = it.tp$iternext()) {\n            if (!Sk.builtin.checkInt(i)) {\n                throw new Sk.builtin.ValueError(\"sound data must be 8-bit integers\");\n            }\n            i = Sk.builtin.asnum$(i);\n            if (i < 0 || i > 255) {\n                throw new Sk.builtin.ValueError(\"sound data must be 8-bit integers\");\n            }\n            data.push(i);\n        }\n\n        var dataURI = \"data:audio/wav;base64,\" + base64_encode(data);\n\n        return Sk.misceval.callsim(mod.Sound, dataURI);\n    });\n\n    var truncate = function(number) {\n        return Math[number < 0 ? 'ceil' : 'floor'](number);\n    };\n\n    var checkPoint = function(point) {\n        // Check that it is a two element sequence\n        if (!Sk.builtin.checkSequence(point) || point.sq$length() != 2) {\n            return false;\n        };\n\n        // Check that each element is a number\n        if (!Sk.builtin.checkNumber(point.mp$subscript(0)) || !Sk.builtin.checkNumber(point.mp$subscript(1))) {\n            return false;\n        };\n\n        return true;\n    };\n\n    // Find non-printing characters\n    var textRE = /[^\\040-\\176]/;\n\n    // Python canvas class\n    var canvas = function($gbl, $loc) {\n        $loc.__init__ = new Sk.builtin.func(function(self, canvas) {\n            self.canvas = canvas;\n            self.context = self.canvas.getContext('2d');\n            if (!self.context || !self.context.drawImage) {\n                alert(\"Cannot draw on canvas!\");\n                return;\n            };\n            self.__class__ = mod.Canvas;\n        });\n\n        $loc.draw_text = new Sk.builtin.func(function(self, text, point, size, color, face) {\n            Sk.builtin.pyCheckArgs(\"draw_text\", arguments, 5, 6);\n            if (!Sk.builtin.checkString(text)) {\n                throw new Sk.builtin.TypeError(\"text must be a string\");\n            };\n            if (!checkPoint(point)) {\n                throw new Sk.builtin.TypeError(\"point must be a 2 element sequence\");\n            };\n            if (!Sk.builtin.checkNumber(size)) {\n                throw new Sk.builtin.TypeError(\"size must be a number\");\n            };\n            size = Sk.builtin.asnum$(size);\n            if (!Sk.builtin.checkString(color)) {\n                throw new Sk.builtin.TypeError(\"color must be a string\");\n            };\n            if (face !== undefined) {\n                if (!Sk.builtin.checkString(face)) {\n                    throw new Sk.builtin.TypeError(\"font face must be a string\");\n                };                \n                face = Sk.ffi.unwrapo(face);\n                // check if face is valid\n                if (fontfaces[face] !== true) {\n                     throw new Sk.builtin.ValueError(\"'\" + face + \"' is not a valid font face\");\n                };\n            } else {\n                // Default value: serif\n                face = \"serif\";\n            };\n\n            self.context.font = size + \"px \" + face;\n            self.context.fillStyle = Sk.ffi.unwrapo(color);\n            text = Sk.ffi.unwrapo(text);\n\n            // Disallow non-printing characters\n            if (textRE.test(text)) {\n                throw new Sk.builtin.ValueError(\"text may not contain non-printing characters\");\n            };\n\n            self.context.fillText(text, \n                                  Sk.builtin.asnum$(point.mp$subscript(0)), \n                                  Sk.builtin.asnum$(point.mp$subscript(1)));\n\n            return Sk.builtin.none.none$;\n        });\n\n        $loc.draw_point = new Sk.builtin.func(function(self, point, color) {\n            Sk.builtin.pyCheckArgs(\"draw_point\", arguments, 3, 3);\n            if (!checkPoint(point)) {\n                throw new Sk.builtin.TypeError(\"point must be a 2 element sequence\");\n            };\n            if (!Sk.builtin.checkString(color)) {\n                throw new Sk.builtin.TypeError(\"color must be a string\");\n            };\n\n            self.context.fillStyle = Sk.ffi.unwrapo(color);\n            self.context.fillRect(Sk.builtin.asnum$(point.mp$subscript(0)), \n                                  Sk.builtin.asnum$(point.mp$subscript(1)), 1, 1);\n\n            return Sk.builtin.none.none$;\n        });\n\n        $loc.draw_line = new Sk.builtin.func(function(self, pt1, pt2, width, color) {\n            Sk.builtin.pyCheckArgs(\"draw_line\", arguments, 5, 5);\n            if (!checkPoint(pt1)) {\n                throw new Sk.builtin.TypeError(\"point1 must be a 2 element sequence\");\n            };\n            if (!checkPoint(pt2)) {\n                throw new Sk.builtin.TypeError(\"point2 must be a 2 element sequence\");\n            };\n            if (!Sk.builtin.checkNumber(width)) {\n                throw new Sk.builtin.TypeError(\"width must be a number\");\n            } \n            width = Sk.builtin.asnum$(width);\n            if (width <= 0) {\n                throw new Sk.builtin.ValueError(\"width must be a positive number\");\n            };\n            if (!Sk.builtin.checkString(color)) {\n                throw new Sk.builtin.TypeError(\"color must be a string\");\n            };\n\n            self.context.lineWidth = width;\n            self.context.strokeStyle = Sk.ffi.unwrapo(color);\n            self.context.beginPath();\n            self.context.moveTo(Sk.builtin.asnum$(pt1.mp$subscript(0)), \n                                Sk.builtin.asnum$(pt1.mp$subscript(1)));\n            self.context.lineTo(Sk.builtin.asnum$(pt2.mp$subscript(0)), \n                                Sk.builtin.asnum$(pt2.mp$subscript(1)));\n            self.context.stroke();\n\n            return Sk.builtin.none.none$;\n        });\n\n        $loc.draw_circle = new Sk.builtin.func(function(self, center, radius, linewidth, linecolor, fillcolor) {\n            Sk.builtin.pyCheckArgs(\"draw_circle\", arguments, 5, 6);\n            if (!checkPoint(center)) {\n                throw new Sk.builtin.TypeError(\"center must be a 2 element sequence\");\n            };\n            if (!Sk.builtin.checkNumber(radius)) {\n                throw new Sk.builtin.TypeError(\"radius must be a number\");\n            };\n            radius = Sk.builtin.asnum$(radius);\n            if (radius <= 0) {\n                throw new Sk.builtin.ValueError(\"radius must be a positive number\");                \n            };\n            if (!Sk.builtin.checkNumber(linewidth)) {\n                throw new Sk.builtin.TypeError(\"linewidth must be a number\");\n            };\n            linewidth = Sk.builtin.asnum$(linewidth);\n            if (linewidth <= 0) {\n                throw new Sk.builtin.ValueError(\"linewidth must be a positive number\");\n            };\n            if (!Sk.builtin.checkString(linecolor)) {\n                throw new Sk.builtin.TypeError(\"linecolor must be a string\");\n            };\n\n            // Check if fillcolor was specified and it is not None\n            if ((fillcolor !== undefined) && (fillcolor !== Sk.builtin.none.none$)) {\n                if (!Sk.builtin.checkString(fillcolor)) {\n                    throw new Sk.builtin.TypeError(\"fillcolor must be a string\");\n                };                \n            } else {\n                // Default value: no fill - fillcolor is None\n                fillcolor = Sk.builtin.none.none$;\n            };\n\n            self.context.lineWidth = linewidth;\n            self.context.strokeStyle = Sk.ffi.unwrapo(linecolor);\n            if (fillcolor !== Sk.builtin.none.none$) {\n                self.context.fillStyle = Sk.ffi.unwrapo(fillcolor);\n            };\n            self.context.beginPath();\n            self.context.arc(Sk.builtin.asnum$(center.mp$subscript(0)), \n                             Sk.builtin.asnum$(center.mp$subscript(1)),\n                             radius, 0, 2 * Math.PI, false);\n            if (fillcolor !== Sk.builtin.none.none$) {\n                self.context.fill();\n            };\n            self.context.stroke();\n\n            return Sk.builtin.none.none$;\n        });\n\n        $loc.draw_polyline = new Sk.builtin.func(function(self, points, width, color) {\n            Sk.builtin.pyCheckArgs(\"draw_polyline\", arguments, 4, 4);\n            if (!Sk.builtin.checkSequence(points)) {\n                throw new Sk.builtin.TypeError(\"points must be a sequence\");\n            };\n            if (!Sk.builtin.checkNumber(width)) {\n                throw new Sk.builtin.TypeError(\"width must be a number\");\n            };\n            width = Sk.builtin.asnum$(width);\n            if (width <= 0) {\n                throw new Sk.builtin.ValueError(\"width must be a positive number\");\n            };\n            if (!Sk.builtin.checkString(color)) {\n                throw new Sk.builtin.TypeError(\"color must be a string\");\n            };\n\n            self.context.lineWidth = width;\n            self.context.strokeStyle = Sk.ffi.unwrapo(color);\n            self.context.beginPath();\n            var point = points.mp$subscript(0);\n            if (!checkPoint(point)) {\n                throw new Sk.builtin.TypeError(\"each point in points must be a 2 element sequence\");\n            };\n            self.context.moveTo(Sk.builtin.asnum$(point.mp$subscript(0)), \n                                Sk.builtin.asnum$(point.mp$subscript(1)));\n            for (i=1; i<points.sq$length(); i++) {\n                point = points.mp$subscript(i);\n                if (!checkPoint(point)) {\n                    throw new Sk.builtin.TypeError(\"each point in points must be a 2 element sequence\");\n                };\n                self.context.lineTo(Sk.builtin.asnum$(point.mp$subscript(0)), \n                                    Sk.builtin.asnum$(point.mp$subscript(1)));\n            }\n            self.context.stroke();\n\n            return Sk.builtin.none.none$;\n        });\n\n        $loc.draw_polygon = new Sk.builtin.func(function(self, points, linewidth, linecolor, fillcolor) {\n            Sk.builtin.pyCheckArgs(\"draw_polygon\", arguments, 4, 5);\n            if (!Sk.builtin.checkSequence(points)) {\n                throw new Sk.builtin.TypeError(\"points must be a sequence\");\n            };\n            if (!Sk.builtin.checkNumber(linewidth)) {\n                throw new Sk.builtin.TypeError(\"linewidth must be a number\");\n            };\n            linewidth = Sk.builtin.asnum$(linewidth);\n            if (linewidth <= 0) {\n                throw new Sk.builtin.ValueError(\"linewidth must be a positive number\");\n            };\n            if (!Sk.builtin.checkString(linecolor)) {\n                throw new Sk.builtin.TypeError(\"linecolor must be a string\");\n            };\n\n            // Check if fillcolor was specified and it is not None\n            if ((fillcolor !== undefined) && (fillcolor !== Sk.builtin.none.none$)) {\n                if (!Sk.builtin.checkString(fillcolor)) {\n                    throw new Sk.builtin.TypeError(\"fillcolor must be a string\");\n                };                \n            } else {\n                // Default value: no fill - fillcolor is None\n                fillcolor = Sk.builtin.none.none$;\n            };\n\n            self.context.lineWidth = linewidth;\n            self.context.strokeStyle = Sk.ffi.unwrapo(linecolor);\n            if (fillcolor !== Sk.builtin.none.none$) {\n                self.context.fillStyle = Sk.ffi.unwrapo(fillcolor);\n            };\n            self.context.beginPath();\n            var point = points.mp$subscript(0);\n            var point0x = Sk.builtin.asnum$(point.mp$subscript(0));\n            var point0y = Sk.builtin.asnum$(point.mp$subscript(1));\n            if (!checkPoint(point)) {\n                throw new Sk.builtin.TypeError(\"each point in points must be a 2 element sequence\");\n            };\n            self.context.moveTo(point0x, point0y);\n            for (i=1; i<points.sq$length(); i++) {\n                point = points.mp$subscript(i);\n                if (!checkPoint(point)) {\n                    throw new Sk.builtin.TypeError(\"each point in points must be a 2 element sequence\");\n                };\n               self.context.lineTo(Sk.builtin.asnum$(point.mp$subscript(0)), \n                                    Sk.builtin.asnum$(point.mp$subscript(1)));\n            }\n            self.context.lineTo(point0x, point0y);\n            self.context.closePath();\n            if (fillcolor !== Sk.builtin.none.none$) {\n                self.context.fill();\n            };\n            self.context.stroke();\n\n            return Sk.builtin.none.none$;\n        });\n\n        $loc.draw_image = new Sk.builtin.func(function(self, image, srcpos, \n                                                       srcdim, dstpos, dstdim,\n                                                       rot) {\n            Sk.builtin.pyCheckArgs(\"draw_image\", arguments, 6, 7);\n            var im = null;\n            if ((image !== null) && (image.__class__ == mod.Image)) {\n                im = image.image;\n            }\n            else if ((image !== null) && (image.__class__ == mod.Canvas)) {\n                im = image.canvas;\n            }\n            else {\n                throw new Sk.builtin.TypeError(\"image must be an image\");\n            };\n            if (!checkPoint(srcpos)) {\n                throw new Sk.builtin.TypeError(\"source center must be a 2 element sequence\");\n            };\n            if (!checkPoint(srcdim)) {\n                throw new Sk.builtin.TypeError(\"source dimensions must be a 2 element sequence\");\n            };\n            if (!checkPoint(dstpos)) {\n                throw new Sk.builtin.TypeError(\"destination center must be a 2 element sequence\");\n            };\n            if (!checkPoint(dstdim)) {\n                throw new Sk.builtin.TypeError(\"destination dimensions must be a 2 element sequence\");\n            };\n            if (rot !== undefined) {\n                if (!Sk.builtin.checkNumber(rot)) {\n                    throw new Sk.builtin.TypeError(\"rotation must be a number\");\n                };                \n            };\n\n            var srcx = Sk.builtin.asnum$(srcpos.mp$subscript(0));\n            var srcy = Sk.builtin.asnum$(srcpos.mp$subscript(1));\n            var srcw = Sk.builtin.asnum$(srcdim.mp$subscript(0));\n            var srch = Sk.builtin.asnum$(srcdim.mp$subscript(1));\n            var dstx = Sk.builtin.asnum$(dstpos.mp$subscript(0));\n            var dsty = Sk.builtin.asnum$(dstpos.mp$subscript(1));\n            var dstw = Sk.builtin.asnum$(dstdim.mp$subscript(0));\n            var dsth = Sk.builtin.asnum$(dstdim.mp$subscript(1));\n\n            if (rot === undefined) {\n                rot = 0;\n            };\n            rot = Sk.builtin.asnum$(rot);\n\n            if ((srcw <= 0) || (srch <= 0) || (dstw <= 0) || (dsth <=0)) {\n                throw new Sk.builtin.ValueError(\"image dimensions must be > 0\");\n            };\n\n            srcx = truncate(srcx - srcw / 2);\n            srcy = truncate(srcy - srch / 2);\n            var dstoffx = truncate(- dstw / 2);\n            var dstoffy = truncate(- dsth / 2);\n\n            if ((srcx < 0) || (srcy < 0)) {\n                // Do not draw anything\n                return;\n            };\n            \n            if ((srcx + srcw > im.width) \n                || (srcy + srch > im.height)) {\n                // Safari: Do not draw anything\n                return;\n            };\n\n            self.context.save();\n            self.context.translate(dstx, dsty);\n            self.context.rotate(rot);\n            self.context.drawImage(im, \n                                   srcx, srcy, srcw, srch,\n                                   dstoffx, dstoffy, dstw, dsth);\n            self.context.restore();\n\n            return Sk.builtin.none.none$;\n        });\n    };\n\n    mod.Canvas = Sk.misceval.buildClass(mod, canvas, 'Canvas', []);\n\n    var create_canvas = function(win, width, height, border) {\n        var canvas = win.document.createElement(\"canvas\");\n\n        canvas.width = width;\n        canvas.height = height;\n        canvas.style.border = border.toString() + 'px solid black';\n        canvas.style.cssFloat = \"right\";\n        canvas.setAttribute('tabindex', '0');\n        canvas.onselectstart = function () {\n            // Prevent weird selection on double click\n            return false;\n        };\n\n        return canvas;\n    };\n\n    mod.create_invisible_canvas = new Sk.builtin.func(function(width, height) {\n        Sk.builtin.pyCheckArgs(\"create_invis_canvas\", arguments, 2, 2);\n        if (!Sk.builtin.checkInt(width)) {\n            throw new Sk.builtin.TypeError(\"width must be an integer\");\n        }\n        if (!Sk.builtin.checkInt(height)) {\n            throw new Sk.builtin.TypeError(\"height must be an integer\");\n        }\n\n        var canvas = create_canvas(window, Sk.builtin.asnum$(width), Sk.builtin.asnum$(height), 0);\n        var pycanvas = Sk.misceval.callsim(mod.Canvas, canvas);\n        return pycanvas;\n    });\n\n    // Control class\n    var control = function($gbl, $loc) {\n        $loc.__init__ = new Sk.builtin.func(function(self, object) {\n            self._object = object;\n        });\n\n        $loc.get_text = new Sk.builtin.func(function(self) {\n            Sk.builtin.pyCheckArgs(\"get_text\", arguments, 1, 1);\n            return Sk.ffi.basicwrap(self._object.textContent);\n        });\n\n        $loc.set_text = new Sk.builtin.func(function(self, text) {\n            Sk.builtin.pyCheckArgs(\"set_text\", arguments, 2, 2);\n\t    var s = new Sk.builtin.str(text);\n            self._object.textContent = Sk.ffi.unwrapo(s);\n        });\n    };\n\n    mod.Control = Sk.misceval.buildClass(mod, control, 'Control', []);\n\n    // Text Area Control class\n    var textareacontrol = function($gbl, $loc) {\n        $loc.__init__ = new Sk.builtin.func(function(self, object) {\n            self._object = object;\n        });\n\n        $loc.get_text = new Sk.builtin.func(function(self) {\n            Sk.builtin.pyCheckArgs(\"get_text\", arguments, 1, 1);\n            return Sk.ffi.basicwrap(self._object.value);\n        });\n\n        $loc.set_text = new Sk.builtin.func(function(self, text) {\n            Sk.builtin.pyCheckArgs(\"set_text\", arguments, 2, 2);\n\t    var s = new Sk.builtin.str(text);\n            self._object.value = Sk.ffi.unwrapo(s);\n        });\n    };\n\n    mod.TextAreaControl = Sk.misceval.buildClass(mod, textareacontrol, 'TextAreaControl', []);\n\n    var statusBox = function(text, offset, width) {\n        var box = document.createElement(\"div\");\n        box.textContent = text;\n        box.style.width = (width-12) + \"px\";\n        box.style.position = \"absolute\";\n        box.style.bottom = offset + \"px\";\n        box.style.border = \"1px solid black\";\n        box.style.paddingLeft = \"5px\";\n        box.style.paddingRight = \"5px\";\n        return box;\n    };\n\n    var canvasCoords = function(canvas, evt) {\n        // Get canvas position\n        var curr = canvas;\n        var top = 0;\n        var left = 0;\n        while (curr && curr.tagName != 'BODY') {\n            top  += curr.offsetTop;\n            left += curr.offsetLeft;\n            curr = curr.offsetParent;\n        }\n\n        // Return relative mouse position\n        return {\n            x: evt.pageX - left,\n            y: evt.pageY - top\n        };                \n    };\n\n    // Key map\n    mod.KEY_MAP = Sk.builtin.dict([]);\n    var i;\n    var code2key = {};\n\n    // Add letters\n    for (i=65; i<=90; i++) {\n        // Lowercase\n        var ch = String.fromCharCode(i+32);\n        mod.KEY_MAP.mp$ass_subscript(Sk.ffi.basicwrap(ch), \n                                     Sk.builtin.assk$(i, Sk.builtin.nmber.int$));\n        code2key[i] = ch;\n\n        // Uppercase\n        ch = String.fromCharCode(i);        \n        mod.KEY_MAP.mp$ass_subscript(Sk.ffi.basicwrap(ch),\n                                     Sk.builtin.assk$(i, Sk.builtin.nmber.int$));\n    };\n    // Add numbers\n    for (i=48; i<=57; i++) {\n        var ch = String.fromCharCode(i);\n        mod.KEY_MAP.mp$ass_subscript(Sk.ffi.basicwrap(ch),\n                                     Sk.builtin.assk$(i, Sk.builtin.nmber.int$));\n        code2key[i] = ch;\n    };\n    // Add space\n    mod.KEY_MAP.mp$ass_subscript(Sk.ffi.basicwrap(\"space\"), \n                                 Sk.builtin.assk$(32, Sk.builtin.nmber.int$));\n    code2key[32] = \"space\";\n    // Add arrows\n    mod.KEY_MAP.mp$ass_subscript(Sk.ffi.basicwrap(\"left\"),\n                                 Sk.builtin.assk$(37, Sk.builtin.nmber.int$));\n    mod.KEY_MAP.mp$ass_subscript(Sk.ffi.basicwrap(\"up\"),\n                                 Sk.builtin.assk$(38, Sk.builtin.nmber.int$));\n    mod.KEY_MAP.mp$ass_subscript(Sk.ffi.basicwrap(\"right\"), \n                                 Sk.builtin.assk$(39, Sk.builtin.nmber.int$));\n    mod.KEY_MAP.mp$ass_subscript(Sk.ffi.basicwrap(\"down\"), \n                                 Sk.builtin.assk$(40, Sk.builtin.nmber.int$));\n    code2key[37] = String.fromCharCode(0x2190); // \"left\";\n    code2key[38] = String.fromCharCode(0x2191); // \"up\";  \n    code2key[39] = String.fromCharCode(0x2192); // \"right\";\n    code2key[40] = String.fromCharCode(0x2193); // \"down\";\n    \n    // Python frame class\n    var frame = function($gbl, $loc) {\n        $loc.__init__ = new Sk.builtin.func(function(self, title, \n                                                     canvas_width, \n                                                     canvas_height, \n                                                     control_width) {\n            var framediv;\n\n            // Save parameters\n            self.title = title;\n            self.width = Sk.builtin.asnum$(canvas_width);\n            self.height = Sk.builtin.asnum$(canvas_height);\n            if (control_width === undefined) {\n                control_width = 200;\n            } else {\n                control_width = Sk.builtin.asnum$(control_width);\n            }\n            self.ctrlWidth = control_width;\n            self.margin = 23;\n\n            // Initial defaults\n            self.draw_handler = new Sk.builtin.func(function(canvas) {});\n            self.background = \"#000000\";\n\n            // Create frame window\n            var winwidth = self.width + self.ctrlWidth + (self.margin*3) + 4;\n            var winheight = self.height + (self.margin*2) + 4;\n            self.frame_window = window.open('','myframe',\n                                            'width='+winwidth\n                                            +',height='+winheight\n                                            +',location=0'\n                                            +',menubar=0'\n                                            +',toolbar=0'\n                                            +',directories=0'\n                                            +',status=0'\n                                            +',titlebar=0'\n                                            +',scrollbars=0'\n                                            +',resizeable=1');\n\n            // Build empty document\n\n            // Escape title\n            var jstitle = title.html$deentify();\n\n            var framehtml = '<html>'\n                +             '<head>'\n                +               '<title>'\n                +                 jstitle\n                +               '</title>'\n                +             '</head>'\n                +             '<body>'\n                +               '<div id=\"guiframe\"></div>'\n                +             '</body>'\n                +           '</html>';\n\n            self.frame_window.document.writeln('<!DOCTYPE html>');\n            self.frame_window.document.writeln(framehtml);\n            self.frame_window.document.close();\n\n            // Build GUI areas\n            var framebody = self.frame_window.document.getElementsByTagName(\"body\")[0];\n            framebody.style.margin = \"0px\";\n            \n            // Control Pane\n            self.control = self.frame_window.document.createElement(\"div\");\n            // +4 to match 2px border around canvas\n            self.control.style.height = (self.height+4) + 'px';\n            self.control.style.width = self.ctrlWidth + 'px';\n            self.control.style.position = \"relative\";\n            self.control.style.cssFloat = \"left\";\n\n            // Drawing Canvas\n            self.canvas_border = 2;\n            self.canvas = create_canvas(self.frame_window, self.width, self.height, self.canvas_border);\n\n            self.animationID = null;\n\n            // Key state\n            self.keydown = {};\n            self.keyuphandler = null;\n            self.keydownhandler = null;\n\n            self.canvas.onkeydown = function(evt) {\n                if (!self.keydown[evt.keyCode]) {\n                    self.keydown[evt.keyCode] = true;\n                    if (self.keydownhandler) {\n                        var key = code2key[evt.keyCode];\n                        if (key === undefined) {\n                            key = \"<\" + evt.keyCode + \">\";\n                        }\n                        self.keyevents.textContent = \"Key: Down \" + key;\n                        try {\n                            Sk.setExecStartNow(true);\n                            Sk.currLineNo = self.keydown_lineno;\n                            Sk.misceval.callsim(self.keydownhandler, \n                                                Sk.builtin.assk$(evt.keyCode, Sk.builtin.nmber.int$));\n                        } catch (e) {\n                            Sk.error(e);\n                        };\n                    };\n                };\n            };\n            self.canvas.onkeyup = function(evt) {\n                self.keydown[evt.keyCode] = false;\n                if (self.keyuphandler) {\n                    var key = code2key[evt.keyCode];\n                    if (key === undefined) {\n                        key = \"<\" + evt.keyCode + \">\";\n                    }\n                    self.keyevents.textContent = \"Key: Up \" + key;\n                    try {\n                        Sk.setExecStartNow(true);\n                        Sk.currLineNo = self.keyup_lineno;\n                        Sk.misceval.callsim(self.keyuphandler,\n                                            Sk.builtin.assk$(evt.keyCode, Sk.builtin.nmber.int$));\n                    } catch (e) {\n                        Sk.error(e);\n                    };\n                };\n            };\n\n            // Mouse\n            self.mousedraghandler = null;\n\n            var mousemove = function (evt) {\n                var coords = canvasCoords(self.canvas, evt);\n                // Adjust position to remove border\n                var x = coords.x - self.canvas_border;\n                var y = coords.y - self.canvas_border;\n                if ((x < 0) || (x >= self.width)\n                    || (y < 0) || (y >= self.height)) {                    \n                    // move was in border\n                    return;\n                };\n                var pos = new Sk.builtins['tuple']([Sk.builtin.assk$(x, Sk.builtin.nmber.int$), \n                                                    Sk.builtin.assk$(y, Sk.builtin.nmber.int$)]);\n                self.mouseevents.textContent = \"Mouse: Move - \" + x + \", \" + y;\n                try {\n                    Sk.setExecStartNow(true);\n                    Sk.currLineNo = self.mousedrag_lineno;\n                    Sk.misceval.callsim(self.mousedraghandler, pos);\n                } catch (e) {\n                    Sk.error(e);\n                };\n            };\n\n            var mousedone = function (evt) {\n                self.canvas.removeEventListener(\"mousemove\", mousemove);\n                self.canvas.removeEventListener(\"mouseup\", mousedone);\n                self.canvas.removeEventListener(\"mouseout\", mousedone);\n            };\n\n            self.canvas.onmousedown = function(evt) {\n                if (self.mousedraghandler) {\n                    self.canvas.addEventListener(\"mousemove\", mousemove);\n                    self.canvas.addEventListener(\"mouseup\", mousedone);\n                    self.canvas.addEventListener(\"mouseout\", mousedone);\n                };\n            };\n\n            // Add elements to frame\n            framediv = self.frame_window.document.getElementById(\"guiframe\");\n            framediv.style.width = (self.width + self.ctrlWidth + self.margin + 4) + \"px\";\n            framediv.style.height = (self.height+4) + \"px\";\n            framediv.style.margin = self.margin + \"px\";\n            // framediv.style.overflow = \"auto\";\n            framediv.appendChild(self.control);\n            framediv.appendChild(self.canvas);\n\n            // These need to be added after the control area is on the page\n            // Otherwise, the mouse event box's height cannot be determined\n            self.mouseevents = statusBox(\"Mouse:\", 0, self.ctrlWidth);\n            self.control.appendChild(self.mouseevents);\n            self.keyevents = statusBox(\"Key:\", \n                                       self.mouseevents.offsetHeight + 5, \n                                       self.ctrlWidth);\n            self.control.appendChild(self.keyevents);\n\n            // Store frame\n            frames.push(self);\n\n            // Give the canvas the focus\n            self.canvas.focus();\n        });\n\n        $loc.get_canvas_textwidth = new Sk.builtin.func(function(self, text, size, face) {\n            Sk.builtin.pyCheckArgs(\"draw_text\", arguments, 3, 4);\n            if (!Sk.builtin.checkString(text)) {\n                throw new Sk.builtin.TypeError(\"text must be a string\");\n            };\n            if (!Sk.builtin.checkNumber(size)) {\n                throw new Sk.builtin.TypeError(\"size must be a number\");\n            };\n            size = Sk.builtin.asnum$(size);\n            if (face !== undefined) {\n                if (!Sk.builtin.checkString(face)) {\n                    throw new Sk.builtin.TypeError(\"font face must be a string\");\n                };                \n                face = Sk.ffi.unwrapo(face);\n                // check if face is valid\n                if (fontfaces[face] !== true) {\n                     throw new Sk.builtin.ValueError(\"'\" + face + \"' is not a valid font face\");\n                };\n            } else {\n                // Default value: serif\n                face = \"serif\";\n            };\n                                                 \n            var context = self.canvas.getContext('2d');\n\n            context.font = size + \"px \" + face;\n            text = Sk.ffi.unwrapo(text);\n            var metrics = context.measureText(text);\n            return Sk.builtin.assk$(metrics.width | 0, Sk.builtin.nmber.int$);\n        });\n\n        $loc.set_canvas_background = new Sk.builtin.func(function(self, color) {\n            Sk.builtin.pyCheckArgs(\"set_canvas_background\", arguments, 2, 2);\n            if (!Sk.builtin.checkString(color)) {\n                throw new Sk.builtin.TypeError(\"expected string\");\n            };\n            self.background = Sk.ffi.unwrapo(color);\n\n            return Sk.builtin.none.none$;\n        });\n\n        $loc.get_canvas_image = new Sk.builtin.func(function(self) {\n            Sk.builtin.pyCheckArgs(\"get_canvas_image\", arguments, 1, 1);\n            \n            var imagedata = self.canvas.toDataURL();\n            window.open(imagedata, \"Canvas Image\", \"left=0,top=0,width=\" \n                        + self.canvas.width + \",height=\" + self.canvas.height \n                        + \",toolbar=0,resizeable=0\");\n\n            return Sk.builtin.none.none$;\n        });\n\n        var cancelAnimation = function (frame) {\n            if (frame.animationID) {\n                cancelAnimationFrame(frame.animationID);\n                frame.animationID = null;\n            };            \n        };\n\n        $loc.start = new Sk.builtin.func(function(self) {\n            Sk.builtin.pyCheckArgs(\"start\", arguments, 1, 1);\n\n            // Make the frame visible and start the gui\n            var context = self.canvas.getContext('2d');\n            if (!context || !context.drawImage) {\n                alert(\"Cannot draw on canvas!\");\n                return;\n            };\n            var canvas = Sk.misceval.callsim(mod.Canvas, self.canvas);\n            \n            // Functions for built-in browser animation callback\n            var draw = function () {\n                context.fillStyle = self.background;\n                context.fillRect(0, 0, self.canvas.width, self.canvas.height);\n                try {\n                    Sk.setExecStartNow(true);\n                    Sk.currLineNo = self.draw_lineno;\n                    Sk.misceval.callsim(self.draw_handler, canvas);\n                } catch (e) {\n                    Sk.error(e);\n                }\n            };\n\n            var animate = function animate() {\n                self.animationID = requestAnimationFrame(animate);\n                draw();\n            };\n\n            // Make sure callbacks stop when window is closed\n            self.frame_window.onbeforeunload = function () {\n                // Works for Chrome and FireFox\n                cancelAnimation(self);\n            };\n\n            self.frame_window.onunload = function () {\n                // Needed for Safari\n                cancelAnimation(self);\n            };\n\n            // Request first animation frame\n            self.animationID = requestAnimationFrame(animate);\n\n            return Sk.builtin.none.none$;\n        });\n\n        $loc.stop = new Sk.builtin.func(function(self) {\n            Sk.builtin.pyCheckArgs(\"stop\", arguments, 1, 1);\n\n            self.frame_window.close();\n            cancelAnimation(self);\n\n            return Sk.builtin.none.none$;\n        });\n\n        $loc.add_button = new Sk.builtin.func(function(self, text, handler, width) {\n            Sk.builtin.pyCheckArgs(\"add_button\", arguments, 3, 4);\n            if (!Sk.builtin.checkString(text)) {\n                throw new Sk.builtin.TypeError(\"text must be a string\");\n            };\n            if (!Sk.builtin.checkFunction(handler)) {\n                throw new Sk.builtin.TypeError(\"handler must be a function\");\n            };\n            if (width !== undefined) {\n                if (!Sk.builtin.checkInt(width)) {\n                    throw new Sk.builtin.TypeError(\"width must be an integer\");\n                };                \n                width = Sk.builtin.asnum$(width);\n            };\n\n            var lineno = Sk.currLineNo;\n\n            // Make the actual button\n            var button = document.createElement(\"button\");\n            var br = document.createElement(\"br\");\n            button.type = \"button\";\n            button.textContent = Sk.ffi.unwrapo(text);\n            if (width !== undefined) {\n                button.style.width = width + \"px\";  \n            };\n            button.onclick = function() {\n                try {\n                    Sk.setExecStartNow(true);\n                    Sk.currLineNo = lineno;\n                    Sk.misceval.callsim(handler);  \n                    // Give the canvas back the focus\n                    self.canvas.focus();\n                } catch (e) {\n                    Sk.error(e);\n                }\n            };\n            // Add button to control area\n            self.control.appendChild(button);\n            self.control.appendChild(br);\n            return Sk.misceval.callsim(mod.Control, button);\n        });\n\n        $loc.add_label = new Sk.builtin.func(function(self, text, width) {\n            Sk.builtin.pyCheckArgs(\"add_label\", arguments, 2, 3);\n            if (!Sk.builtin.checkString(text)) {\n                throw new Sk.builtin.TypeError(\"text must be a string\");\n            };\n            if (width !== undefined) {\n                if (!Sk.builtin.checkInt(width)) {\n                    throw new Sk.builtin.TypeError(\"width must be an integer\");\n                };                \n                width = Sk.builtin.asnum$(width);\n            };\n\n            // Make the actual label\n            var label = document.createElement(\"span\");\n            var br = document.createElement(\"br\");\n            label.textContent = Sk.ffi.unwrapo(text);\n            label.style.display = \"inline-block\";\n            if (width !== undefined) {\n                label.style.width = width + \"px\";\n            };\n            // console.log(label.style);\n            // Add label to control area\n            self.control.appendChild(label);\n            self.control.appendChild(br);\n            return Sk.misceval.callsim(mod.Control, label);\n        });\n\n        $loc.add_input = new Sk.builtin.func(function(self, text, handler, width) {\n            Sk.builtin.pyCheckArgs(\"add_input\", arguments, 4, 4);\n            if (!Sk.builtin.checkString(text)) {\n                throw new Sk.builtin.TypeError(\"text must be a string\");\n            };\n            if (!Sk.builtin.checkFunction(handler)) {\n                throw new Sk.builtin.TypeError(\"handler must be a function\");\n            };\n            if (!Sk.builtin.checkInt(width)) {\n                throw new Sk.builtin.TypeError(\"width must be an integer\");\n            };                \n            width = Sk.builtin.asnum$(width);\n\n            var lineno = Sk.currLineNo;\n\n            // Make the actual text field\n            var label = document.createElement(\"span\");\n            var textField = document.createElement(\"textarea\");\n            var br1 = document.createElement(\"br\");\n            var br2 = document.createElement(\"br\");\n            label.textContent = Sk.ffi.unwrapo(text);\n            textField.rows = 1;\n            textField.style.resize = \"none\";\n            textField.style.width = width + \"px\";                \n\n            // Keypress handler to trap \"enter\" key\n            textField.onkeypress = function(evt) {\n                // Call Python handler when \"enter\" is pressed\n                if (evt.keyCode == 13) {\n                    // Don't let the text box contain multiple lines\n                    evt.preventDefault();\n                    try {\n                        var txt = Sk.ffi.basicwrap(textField.value);\n                        Sk.setExecStartNow(true);\n                        Sk.currLineNo = lineno;\n                        Sk.misceval.callsim(handler, txt);\n                        // Give the canvas back the focus\n                        self.canvas.focus();\n                    } catch (e) {\n                        Sk.error(e);\n                    }\n                };\n            };\n\n            // Add text field to control area\n            self.control.appendChild(label);\n            self.control.appendChild(br1);\n            self.control.appendChild(textField);\n            self.control.appendChild(br2);\n            return Sk.misceval.callsim(mod.TextAreaControl, textField);\n        });\n\n        $loc.set_keyup_handler = new Sk.builtin.func(function(self, handler) {\n            Sk.builtin.pyCheckArgs(\"set_keyup_handler\", arguments, 2, 2);\n            if (!Sk.builtin.checkFunction(handler)) {\n                throw new Sk.builtin.TypeError(\"handler must be a function\");\n            };\n\n            self.keyuphandler = handler;\n            self.keyup_lineno = Sk.currLineNo;\n\n            return Sk.builtin.none.none$;\n        });\n\n        $loc.set_keydown_handler = new Sk.builtin.func(function(self, handler) {\n            Sk.builtin.pyCheckArgs(\"set_keydown_handler\", arguments, 2, 2);\n            if (!Sk.builtin.checkFunction(handler)) {\n                throw new Sk.builtin.TypeError(\"handler must be a function\");\n            };\n\n            self.keydownhandler = handler;\n            self.keydown_lineno = Sk.currLineNo;\n\n            return Sk.builtin.none.none$;\n        });\n\n        $loc.set_mouseclick_handler = new Sk.builtin.func(function(self, handler) {\n            Sk.builtin.pyCheckArgs(\"set_mouseclick_handler\", arguments, 2, 2);\n            if (!Sk.builtin.checkFunction(handler)) {\n                throw new Sk.builtin.TypeError(\"handler must be a function\");\n            };\n\n            var lineno = Sk.currLineNo;\n\n            self.canvas.onclick = function(evt) {\n                var coords = canvasCoords(self.canvas, evt);\n                // Adjust position to remove border\n                var x = coords.x - self.canvas_border;\n                var y = coords.y - self.canvas_border;\n                if ((x < 0) || (x >= self.width)\n                    || (y < 0) || (y >= self.height)) {                    \n                    // Click was in border\n                    return;\n                };\n                var pos = new Sk.builtins['tuple']([Sk.builtin.assk$(x, Sk.builtin.nmber.int$), \n                                                    Sk.builtin.assk$(y, Sk.builtin.nmber.int$)]);\n                self.mouseevents.textContent = \"Mouse: Click \" + x + \", \" + y;\n\n                try {\n                    Sk.setExecStartNow(true);\n                    Sk.currLineNo = lineno;\n                    Sk.misceval.callsim(handler, pos);\n                } catch (e) {\n                    Sk.error(e);\n                };\n            };\n\n            return Sk.builtin.none.none$;\n        });\n\n        $loc.set_mousedrag_handler = new Sk.builtin.func(function(self, handler) {\n            Sk.builtin.pyCheckArgs(\"set_mousedrag_handler\", arguments, 2, 2);\n            if (!Sk.builtin.checkFunction(handler)) {\n                throw new Sk.builtin.TypeError(\"handler must be a function\");\n            };\n\n            self.mousedraghandler = handler;\n            self.mousedrag_lineno = Sk.currLineNo;\n\n            return Sk.builtin.none.none$;\n        });\n\n        $loc.set_draw_handler = new Sk.builtin.func(function(self, handler) {\n            Sk.builtin.pyCheckArgs(\"set_draw_handler\", arguments, 2, 2);\n            if (!Sk.builtin.checkFunction(handler)) {\n                throw new Sk.builtin.TypeError(\"handler must be a function\");\n            };\n\n            self.draw_handler = handler;\n            self.draw_lineno = Sk.currLineNo;\n\n            return Sk.builtin.none.none$;\n        });\n    };\n\n\n    mod.Frame = Sk.misceval.buildClass(mod, frame, 'Frame', []);\n\n    mod.create_frame = new Sk.builtin.func(function(title, canvas_width, canvas_height, control_width) {\n        Sk.builtin.pyCheckArgs(\"create_frame\", arguments, 3, 4);\n        if (!Sk.builtin.checkString(title)) {\n            throw new Sk.builtin.TypeError(\"title must be a string\");\n        };\n\n        if (!Sk.builtin.checkNumber(canvas_width)) {\n            throw new Sk.builtin.TypeError(\"canvas width must be a number\");\n        };                \n        if (!Sk.builtin.checkNumber(canvas_height)) {\n            throw new Sk.builtin.TypeError(\"canvas height must be a number\");\n        };                \n\n        if (control_width !== undefined) {\n            if (!Sk.builtin.checkNumber(control_width)) {\n                throw new Sk.builtin.TypeError(\"control width must be a number\");\n            }; \n\n            if (Sk.builtin.asnum$(control_width) < 0) {\n                throw new Sk.builtin.ValueError(\"control width must be >= 0\");\n            };\n        };\n\n\n        if (Sk.builtin.asnum$(canvas_width) < 0) {\n            throw new Sk.builtin.ValueError(\"canvas width must be >= 0\");\n        };\n\n        if (Sk.builtin.asnum$(canvas_height) < 0) {\n            throw new Sk.builtin.ValueError(\"canvas height must be >= 0\");\n        };\n            \n        return Sk.misceval.callsim(mod.Frame, title, canvas_width, canvas_height, control_width);\n    });\n\n    // Python timer class\n    var timer = function($gbl, $loc) {\n        $loc.__init__ = new Sk.builtin.func(function(self, interval, handler) {\n            // Initialize\n            self.interval = interval;\n            self.handler = handler;\n            self._timer = null;\n            self.lineno = Sk.currLineNo;\n\n            // Store timer\n            timers.push(self);\n        });\n\n        $loc.start = new Sk.builtin.func(function(self) {\n            Sk.builtin.pyCheckArgs(\"start\", arguments, 1, 1);\n\n            if (self._timer) {\n                // Already running, ignore\n                return;\n            }\n            // Create new Javascript timer which calls the Python handler\n            self._timer = setInterval(function() {\n                try {\n                    Sk.setExecStartNow(true);\n                    Sk.currLineNo = self.lineno;\n                    Sk.misceval.callsim(self.handler);\n                } catch (e) {\n                    clearInterval(self._timer);\n                    self._timer = null;\n                    Sk.error(e);\n                };                    \n            }, Sk.builtin.asnum$(self.interval));\n\n            return Sk.builtin.none.none$;\n        });\n\n        $loc.stop = new Sk.builtin.func(function(self) {\n            Sk.builtin.pyCheckArgs(\"stop\", arguments, 1, 1);\n\n            // If a Javascript timer exists, stop it and delete it\n            if (self._timer) {\n                clearInterval(self._timer);\n                self._timer = null;\n            }\n\n            return Sk.builtin.none.none$;\n        });\n\n        $loc.get_interval = new Sk.builtin.func(function(self) {\n            Sk.builtin.pyCheckArgs(\"get_interval\", arguments, 1, 1);\n\n            return self.interval;\n        });\n\n        $loc.is_running = new Sk.builtin.func(function(self) {\n            Sk.builtin.pyCheckArgs(\"is_running\", arguments, 1, 1);\n\n            if (self._timer) {\n                return Sk.builtin.bool.true$;\n            } else {\n                return Sk.builtin.bool.false$;\n            }\n        });\n    };\n\n    mod.Timer = Sk.misceval.buildClass(mod, timer, 'Timer', []);\n\n    mod.create_timer = new Sk.builtin.func(function(interval, handler) {\n        Sk.builtin.pyCheckArgs(\"create_timer\", arguments, 2, 2);\n        if (!Sk.builtin.checkNumber(interval)) {\n            throw new Sk.builtin.TypeError(\"interval must be a number\");\n        };                \n        if (!Sk.builtin.checkFunction(handler)) {\n            throw new Sk.builtin.TypeError(\"handler must be a function\");\n        };\n\n        if (Sk.builtin.asnum$(interval) <= 0) {\n            throw new Sk.builtin.ValueError(\"interval must be > 0\");\n        };\n\n        return Sk.misceval.callsim(mod.Timer, interval, handler);        \n    });\n\n    return mod;\n};
</textarea>
<input type="button" value="clean" id="clean"></input>
</form1>
</html>
